package com.jwei.web;

import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

@Controller
public class ESController {

    @Autowired
    private TransportClient client;

    @GetMapping("/get/book/novel")
    public ResponseEntity get(String id) {
        if (id.isEmpty()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
//        GetResponse response = client.prepareGet("book", "novel", "pQXc7HMBWo27D6flAY2G").get();
        GetResponse response = client.prepareGet("book", "novel", id).get();
        if (!response.isExists()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity(response.getSource(), HttpStatus.OK);
    }

    @PostMapping("/add/book/novel")
    public ResponseEntity add(String title, String author, int wordCount,
                              @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date publishDate) {
        try {
            XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject()
                    .field("title", title)
                    .field("author", author)
                    .field("wordCount", wordCount)
                    .field("publishDate", publishDate.getTime())
                    .endObject();

            IndexResponse response = client.prepareIndex("book", "novel").setSource(xContentBuilder).get();
            return new ResponseEntity(response.getId(), HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @PutMapping("/update/book/novel")
    public ResponseEntity update(String id, @RequestParam(value = "title", required = false) String title,
                                 @RequestParam(value = "author", required = false) String author,
                                 @RequestParam(value = "wordCount", required = false) Integer wordCount,
                                 @RequestParam(value = "publishDate", required = false)
                                 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date publishDate) {
        UpdateRequest updateRequest = new UpdateRequest("book", "novel", id);
        try {
            XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject();
            if (title != null) {
                xContentBuilder.field("title", title);
            }
            if (author != null) {
                xContentBuilder.field("author", author);
            }
            if (wordCount != null) {
                xContentBuilder.field("wordCount", wordCount);
            }
            if (publishDate != null) {
                xContentBuilder.field("publishDate", publishDate.getTime());
            }
            xContentBuilder.endObject();
            updateRequest.doc(xContentBuilder);
            UpdateResponse updateResponse = client.update(updateRequest).get();

            return new ResponseEntity(updateResponse.getResult().toString(), HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("/query/book/novel")
    public ResponseEntity query(@RequestParam(value = "title", required = false) String title,
                                @RequestParam(value = "author", required = false) String author,
                                @RequestParam(value = "wordCount", required = false) Integer wordCount,
                                @RequestParam(value = "publishDate", required = false)
                                @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date publishDate,
                                @RequestParam(value = "gtWordCount", defaultValue = "0") Integer gtWordCount,
                                @RequestParam(value = "ltWordCount", required = false) Integer ltWordCount) {
        // 组装查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (title != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("title", title));
        }
        if (author != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("author", author));
        }
        if (wordCount != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("title", wordCount));
        }
        if (publishDate != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("publishDate", publishDate));
        }

        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("wordCount").from(gtWordCount);
        if (ltWordCount != null && ltWordCount > 0) {
            rangeQueryBuilder.to(ltWordCount);
        }
        boolQueryBuilder.filter(rangeQueryBuilder);

        SearchRequestBuilder searchRequestBuilder = client.prepareSearch("book").setTypes("novel")
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(boolQueryBuilder).setFrom(0).setSize(10);

        SearchResponse searchResponse = searchRequestBuilder.get();

        ArrayList<Map<String, Object>> result = new ArrayList<>();
        for (SearchHit searchHitFields : searchResponse.getHits()) {
            result.add(searchHitFields.getSource());
        }

        return new ResponseEntity(result, HttpStatus.OK);
    }

}
